package cn.learn.dao.impl;

import cn.learn.dao.OperationElasticsearchDocDao;
import cn.learn.domain.ElasticsearchQuery;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.stereotype.Repository;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * elasticsearch的操作
 *
 * @author huangyezhan
 * @version 1.0
 * @date 2020年06月30日11:18
 */
@Repository
public class OperationElasticsearchDocDaoImpl implements OperationElasticsearchDocDao {
    private final BulkProcessor       bulkProcessor;
    private final RestHighLevelClient restHighLevelClient;

    public OperationElasticsearchDocDaoImpl(BulkProcessor bulkProcessor, RestHighLevelClient restHighLevelClient) {
        this.bulkProcessor = bulkProcessor;
        this.restHighLevelClient = restHighLevelClient;
    }


    @Override
    public boolean createIndexMapping(String indexName, String mapping) throws IOException {
        String json = "{\n" +
                "    \"properties\": {\n" +
                "      \"id\":{\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"nsrsbh\":{\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"nsrmc\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"ik_max_word\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"location\": {\n" +
                "        \"type\": \"geo_point\"\n" +
                "      }\n" +
                "    }\n" +
                "  }";

        if (mapping != null) {
            json = mapping;
        }
        CreateIndexRequest request = new CreateIndexRequest(indexName);
        request.mapping(json, XContentType.JSON);

        CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
        return response.isAcknowledged() && response.isShardsAcknowledged();
    }

    @Override
    public boolean deleteIndex(String index) throws IOException {
        DeleteIndexRequest   request = new DeleteIndexRequest(index);
        AcknowledgedResponse delete  = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
        return delete.isAcknowledged();
    }

    @Override
    public void bulk(List<Map<String, String>> data, String index)  {
        for (Map<String, String> nsrxx : data) {
            bulkProcessor.add(new IndexRequest(index)
                    .id(nsrxx.get("id"))
                    .source(nsrxx));
        }
    }

    @Override
    public SearchHits query(ElasticsearchQuery qo) throws IOException {
        //创建一个搜索请求
        SearchRequest searchRequest = new SearchRequest(qo.getIndex());
        //创建一个搜索资源对象，
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.query(QueryBuilders.matchQuery(qo.getColumnName(), qo.getKeyword()));
        //分页处理，在1w条数据内；用from size做最好，默认就是top10
        //默认查询前1w条数据
        searchSourceBuilder.from(qo.getFrom()).size(qo.getSize());
        searchRequest.source(searchSourceBuilder);

        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        return search.getHits();
    }

    @Override
    public SearchHits geoBoundingBox(ElasticsearchQuery qo, String topLeft, String bottomRight) throws IOException {
        String[] topStr    = topLeft.split(",");
        double   left      = Double.parseDouble(topStr[0]);
        double   top       = Double.parseDouble(topStr[1]);
        String[] bottomStr = bottomRight.split(",");
        double   right     = Double.parseDouble(bottomStr[0]);
        double   bottom    = Double.parseDouble(bottomStr[1]);

        //创建一个搜索请求
        SearchRequest searchRequest = new SearchRequest(qo.getIndex());
        //创建一个搜索资源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder    builder             = QueryBuilders.boolQuery();

        if (qo.getKeyword() != null && qo.getKeyword() != null) {
            //匹配查询的列名
            builder.must(QueryBuilders.matchQuery(qo.getColumnName(), qo.getKeyword()));
        } else {
            //所有
            builder.must(QueryBuilders.matchAllQuery());
        }
        //矩形地图查询
        builder.filter(QueryBuilders.geoBoundingBoxQuery("location").setCorners(top, left, bottom, right));

        searchSourceBuilder.query(builder);
        //分页处理，在1w条数据内；用from size做最好，默认就是top10
        //默认查询前1w条数据
        if (qo.getFrom() > -1 && qo.getSize() > 0) {
            searchSourceBuilder.from(0).size(qo.getSize());
        }

        searchRequest.source(searchSourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        return search.getHits();
    }

    @Override
    public SearchHits geoPolygon(ElasticsearchQuery qo, List<GeoPoint> points) throws IOException {
        SearchRequest       searchRequest       = new SearchRequest(qo.getIndex());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder    builder             = this.boolQueryBuilder(qo);
        builder.filter(QueryBuilders.geoPolygonQuery("location", points));
        searchSourceBuilder.query(builder);
        if (qo.getFrom() > -1 && qo.getSize() > 0) {
            searchSourceBuilder.from(0).size(qo.getSize());
        }
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        return search.getHits();
    }


    @Override
    public SearchHits officialDocument(ElasticsearchQuery qo) throws IOException {
        //创建一个搜索资源对象，
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.should(QueryBuilders.matchQuery("issuingAgency",qo.getKeyword()));
        boolQuery.should(QueryBuilders.matchQuery("docName",qo.getKeyword()));
        boolQuery.should(QueryBuilders.matchQuery("content",qo.getKeyword()));

        searchSourceBuilder.query(boolQuery);

        //高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<span style='background: yellow'>");
        highlightBuilder.postTags("</span>");
        highlightBuilder.field("issuingAgency");
        highlightBuilder.field("docName");
        highlightBuilder.field("content");

        //如果要多个字段高亮,这项要为false
        highlightBuilder.requireFieldMatch(true);
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        //最大高亮分片数
        highlightBuilder.fragmentSize(800000);
        //从第一个分片获取高亮片段
        highlightBuilder.numOfFragments(0);

        /*HighlightBuilder.Field issuingAgency = new HighlightBuilder.Field("issuingAgency");
        issuingAgency.highlighterType("unified");
        highlightBuilder.field(issuingAgency);

        HighlightBuilder.Field docName = new HighlightBuilder.Field("docName");
        docName.highlighterType("unified");
        highlightBuilder.field(docName);

        HighlightBuilder.Field content = new HighlightBuilder.Field("content");
        content.highlighterType("unified");
        highlightBuilder.field(content);*/

        searchSourceBuilder.highlighter(highlightBuilder);


        //分页处理，在1w条数据内；用from size做最好，默认就是top10
        //默认查询前1w条数据
        searchSourceBuilder.from(qo.getFrom()).size(qo.getSize());


        //创建一个搜索请求
        SearchRequest searchRequest = new SearchRequest(qo.getIndex());
        searchRequest.source(searchSourceBuilder);


        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        return search.getHits();
    }




    private BoolQueryBuilder boolQueryBuilder(ElasticsearchQuery qo) {
        BoolQueryBuilder builder = QueryBuilders.boolQuery();

        if (qo.getKeyword() != null && qo.getKeyword() != null) {
            //匹配查询的列名
            builder.must(QueryBuilders.matchQuery(qo.getColumnName(), qo.getKeyword()));
        } else {
            //所有
            builder.must(QueryBuilders.matchAllQuery());
        }
        return builder;
    }


}
